package com.fu.mr.bluetoothdchat;

import android.Manifest;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;


/**
 * <pre>
 *     author : Mr.Fu
 *     e-mail : 18622268981@163.com
 *     time   : 2020/03/06
 *     desc   : 蓝牙设备显示列表界面
 *     version: 1.0     实现显示已配对蓝牙设备列表的功能
 *              2.0     完善 搜索,配对,连接以及刷新列表等功能
 *                  1.  区分设备类型为 已配对设备和其他(未配对)设备
 *                  2.  自定义标题栏,添加"搜索按钮",并实现点击"搜索"按钮,执行搜索周围蓝牙设备的功能
 *                  3.  实现 ExpandableListView 替换 ListView,并实现单个条目的点击事件(连接,配对)
 *                  4.  根据不同设备的类型,使用不同的图标进行区别
 *                  5.  实现点击"未配对"设备条目,执行蓝牙配对操作,并将配对的设备添加到"已配对"列表
 * </pre>
 */

public class DevicesListActivity extends AppCompatActivity {

    private static final String TAG = DevicesListActivity.class.getSimpleName();

    private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1001;

    private ImageView mIvBackAction;
    private ImageView mIvSearchAction;
    private ProgressDialog mProgressDialog;
    private TextView mTvTitle;
    private TextView mTvTip;
    private ExpandableListView mElvDevices;

    private DevicesListAdapter mDevicesListAdapter;
    private BluetoothReceiver mBluetoothReceiver;

    private List<BluetoothDevice> mBondedDevicesList = new ArrayList<>();
    private List<BluetoothDevice> mOtherDevicesList = new ArrayList<>();

    public static Intent getCallingIntent(Context context) {

        return new Intent(context, DevicesListActivity.class);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_devices_list);

        initView();
        initBluetooth();
    }



    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {

        for (int i = 0; i < permissions.length; i++) {
            if (permissions[i].equals(Manifest.permission.ACCESS_COARSE_LOCATION)) {
                int grantResult = grantResults[i];
                if (grantResult == PackageManager.PERMISSION_GRANTED) {
                    startDiscovery();
                } else {

                }
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        unregisterBluetoothReceiver();
    }

    private void initView() {

        mTvTitle = findViewById(R.id.tv_title);
        mTvTip = findViewById(R.id.tv_tip);
        mIvBackAction = findViewById(R.id.iv_back);
        mIvSearchAction = findViewById(R.id.iv_search);
        mElvDevices = findViewById(R.id.elv_devices);
        mDevicesListAdapter = new DevicesListAdapter(
                this, mBondedDevicesList, mOtherDevicesList);
        mElvDevices.setAdapter(mDevicesListAdapter);

        mIvBackAction.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                finish();
            }
        });
        mIvSearchAction.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // 2020/3/16 请求权限(针对6.0及以上版本)并执行蓝牙搜索操作
                requestPermission();
            }
        });
        mElvDevices.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
            @Override
            public boolean onChildClick(ExpandableListView expandableListView, View view,
                                        int groupPosition, int childPosition, long id) {

                if (groupPosition == 0) {
                    // 2020/3/16 执行蓝牙连接操作
                    BluetoothDevice device = mBondedDevicesList.get(childPosition);
                    Log.d(TAG, "已配对设备: " + device.getName());
                    LiveDataBus.get().with("KEY_BLUETOOTH_DEVICE").setValue(device);
                    finish();
                } else {
                    // 2020/3/16 执行蓝牙配对操作
                    BluetoothDevice device = mOtherDevicesList.get(childPosition);
                    Log.d(TAG, "其他设备: " + device.getName());
                    try {
                        Method createBondMethod = BluetoothDevice.class.getMethod("createBond");
                        createBondMethod.invoke(device);
                        Log.d(TAG, "开始配对");
                    } catch (Exception e) {
                        e.printStackTrace();
                        refreshBluetoothBondState("与设备 " + device.getName() + " 配对异常");
                    }
                }
                return false;
            }
        });
    }

    private void requestPermission() {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION)
                    != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
                        PERMISSION_REQUEST_COARSE_LOCATION);
            } else {
                startDiscovery();
            }
        } else {
            startDiscovery();
        }
    }

    private void startDiscovery() {

        showSearchProgressDialog();
        mTvTitle.setText("搜索设备中...");
        mElvDevices.expandGroup(1);
        BluetoothManager.getInstance().startDiscovery();
    }

    private void initBluetooth() {

        if (!BluetoothManager.getInstance().isSupported()) {
            Toast.makeText(this, "当前设备不支持蓝牙", Toast.LENGTH_SHORT).show();
            return;
        }

        registerBluetoothReceiver();

        BluetoothManager.getInstance().open();

        Set<BluetoothDevice> bondedDevices = BluetoothManager.getInstance().getBondedDevices();
        mBondedDevicesList.addAll(bondedDevices);
        mDevicesListAdapter.updateBondedDevicesList(mBondedDevicesList);
        if (mBondedDevicesList.size() == 0) {
            mElvDevices.expandGroup(0);
            mTvTip.setVisibility(View.VISIBLE);
        }
    }

    private void registerBluetoothReceiver() {

        if (mBluetoothReceiver == null) {
            mBluetoothReceiver = new BluetoothReceiver();
        }
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothDevice.ACTION_FOUND);
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
        registerReceiver(mBluetoothReceiver, filter);
    }

    private void unregisterBluetoothReceiver() {

        if (mBluetoothReceiver != null) {
            unregisterReceiver(mBluetoothReceiver);
            mBluetoothReceiver = null;
        }
    }

    private void addOtherDevicesList(BluetoothDevice device) {

        if (!mOtherDevicesList.contains(device)) {
            mOtherDevicesList.add(device);
            mDevicesListAdapter.updateOtherDevicesList(mOtherDevicesList);
            mTvTip.setVisibility(View.GONE);
        }
    }

    private void showSearchProgressDialog() {

        if (mProgressDialog == null) {
            mProgressDialog = new ProgressDialog(this);
        }
        mProgressDialog.setTitle("蓝牙串口");
        mProgressDialog.setMessage("正在搜索设备... ");
        mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        mProgressDialog.show();
    }

    private void hideSearchProgressDialog() {

        if (mProgressDialog != null && mProgressDialog.isShowing()) {
            mProgressDialog.dismiss();
        }
    }

    private void refreshBluetoothBondState(String state) {

        mTvTip.setVisibility(View.VISIBLE);
        mTvTip.setText(state);
    }

    class BluetoothReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {

            String action = intent.getAction();
            Log.w(TAG, action);
            assert action != null;
            if (action.equals(BluetoothDevice.ACTION_FOUND)) {
                Log.w(TAG, "ACTION_FOUND");
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                if (device != null) {
                    //  判断是否配对过
                    if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
                        addOtherDevicesList(device);
                    }
                }
            } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
                Log.w(TAG, "ACTION_DISCOVERY_FINISHED");
                hideSearchProgressDialog();
                mTvTitle.setText("选择一个设备进行连接");
            } else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                if (device.getBondState() == BluetoothDevice.BOND_BONDING) {
                    Log.w(TAG, "正在配对");
                    refreshBluetoothBondState("正在与设备 " + device.getName() + " 进行配对操作");
                } else if (device.getBondState() == BluetoothDevice.BOND_BONDED) {
                    Log.d(TAG, "完成配对");
                    // 2020/3/16 刷新设备列表
                    mBondedDevicesList.add(device);
                    mDevicesListAdapter.updateBondedDevicesList(mBondedDevicesList);
                    mOtherDevicesList.remove(device);
                    mDevicesListAdapter.updateOtherDevicesList(mOtherDevicesList);
                    refreshBluetoothBondState("与设备 " + device.getName() + " 完成配对");
                    mElvDevices.expandGroup(0);
                } else if (device.getBondState() == BluetoothDevice.BOND_NONE) {
                    Log.e(TAG, "取消配对");
                    refreshBluetoothBondState("与设备 " + device.getName() + " 取消配对/配对失败");
                }
            }
        }
    }

    class DevicesListAdapter extends BaseExpandableListAdapter {

        private List<BluetoothDevice> mmBondedDevicesList;
        private List<BluetoothDevice> mmOtherDevicesList;
        private LayoutInflater mmInflater;

        private String mmGroupData[] = {
                getResources().getString(R.string.bonded_device),
                getResources().getString(R.string.other_device)
        };

        public DevicesListAdapter(Context context, List<BluetoothDevice> bondedDevicesList,
                                  List<BluetoothDevice> otherDevicesList) {

            this.mmBondedDevicesList = bondedDevicesList;
            this.mmOtherDevicesList = otherDevicesList;
            this.mmInflater = LayoutInflater.from(context);
        }

        @Override
        public int getGroupCount() {

            return mmGroupData.length;
        }

        @Override
        public int getChildrenCount(int groupPosition) {

            if (groupPosition == 0) {
                return mmBondedDevicesList.size();
            } else {
                return mmOtherDevicesList.size();
            }
        }

        @Override
        public String getGroup(int groupPosition) {

            return mmGroupData[groupPosition];
        }

        @Override
        public BluetoothDevice getChild(int groupPosition, int childPosition) {

            if (groupPosition == 0) {
                return mmBondedDevicesList.get(childPosition);
            } else {
                return mmOtherDevicesList.get(childPosition);
            }
        }

        @Override
        public long getGroupId(int groupPosition) {

            return groupPosition;
        }

        @Override
        public long getChildId(int groupPosition, int childPosition) {

            return childPosition;
        }

        /**
         * 表示数据是否稳定,对监听事件有影响
         *
         * @return
         */
        @Override
        public boolean hasStableIds() {

            return true;
        }

        /**
         * 确定一个组的展示视图
         *
         * @param groupPosition
         * @param isExpanded
         * @param convertView
         * @param parent
         * @return
         */
        @Override
        public View getGroupView(int groupPosition, boolean isExpanded,
                                 View convertView, ViewGroup parent) {

            if (convertView == null) {
                convertView = mmInflater.inflate(R.layout.group_item_elv_devices,
                        parent, false);
            }
            TextView groupTextView = convertView.findViewById(R.id.tv_group);

            groupTextView.setText(mmGroupData[groupPosition]);

            return convertView;
        }

        @Override
        public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
                                 View convertView, ViewGroup parent) {

            if (convertView == null) {
                convertView = mmInflater.inflate(R.layout.child_item_elv_devices,
                        parent, false);
            }
            TextView nameTextView = convertView.findViewById(R.id.tv_bluetooth_name);
            TextView addressTextView = convertView.findViewById(R.id.tv_bluetooth_address);

            BluetoothDevice device;
            if (groupPosition == 0) {
                device = mmBondedDevicesList.get(childPosition);
            } else {
                device = mmOtherDevicesList.get(childPosition);
            }
            nameTextView.setText(TextUtils.isEmpty(device.getName()) ? "Unknown" : device.getName());
            addressTextView.setText(device.getAddress());

            return convertView;
        }

        @Override
        public boolean isChildSelectable(int groupPosition, int childPosition) {

            return true;
        }

        private void updateBondedDevicesList(List<BluetoothDevice> deviceList) {

            this.mmBondedDevicesList = deviceList;
            notifyDataSetChanged();
        }

        private void updateOtherDevicesList(List<BluetoothDevice> deviceList) {

            this.mmOtherDevicesList = deviceList;
            notifyDataSetChanged();
        }
    }
}
